from sqlalchemy.orm import joinedload

from app.models import Recipe
from app.models.food_categories import FoodCategory
from app.models.foods import Food
from app.models.meal_foods import MealFood
from app.models.meal import Meal
from app import db
from sqlalchemy.orm.exc import NoResultFound

class FoodService:
    @staticmethod
    def get_all_categories():
        # 查询所有的一级分类（category_code 长度为 2）
        primary_categories = FoodCategory.query.filter(db.func.length(FoodCategory.category_code) == 2).all()

        category_hierarchy = []

        for category in primary_categories:
            # 获取每个一级分类下的所有二级分类，条件是：category_code 的前两位与 parent_id 相等
            secondary_categories = FoodCategory.query.filter(
                db.func.substring(FoodCategory.category_code, 1, 2) == category.category_code
            ).all()

            children = []
            for index, sub_category in enumerate(secondary_categories):
                if index == 0:
                    continue  # 跳过第一次循环
                children.append({
                    'category_code': sub_category.category_code,
                    'category_name': sub_category.category_name,
                    'thumbnail': f'/images/groceries.png',  # 假设你有这个字段
                    # 'thumbnail': sub_category.thumbnail,  # 假设你有这个字段
                    'children': []  # 二级分类下没有子分类，默认为空
                })

            category_hierarchy.append({
                'category_code': category.category_code,
                'category_name': category.category_name,
                'thumbnail': f'/images/groceries.png',  # 假设你有这个字段
                # 'thumbnail': category.thumbnail,  # 假设你有这个字段
                'children': children
            })

        return category_hierarchy

    @staticmethod
    def get_category_by_code(category_code):
        # 根据 category_code 获取分类信息
        category = FoodCategory.query.filter_by(category_code=category_code).first()
        if not category:
            return None
        # 获取所有子分类
        children = FoodCategory.query.filter_by(parent_id=category_code).all()
        children_data = [{
            'category_code': child.category_code,
            'category_name': child.category_name,
            'thumbnail': child.thumbnail  # 假设有这个字段
        } for child in children]

        return {
            'category_code': category.category_code,
            'category_name': category.category_name,
            'thumbnail': category.thumbnail,  # 假设你有这个字段
            'children': children_data
        }

    def _get_thumbnail_url(self, category_name):
        """
        根据类别名称返回缩略图URL
        :param category_name: 类别名称
        :return: 缩略图的URL
        """
        # 这里可以根据类别名称返回特定的URL，以下是示例
        category_thumbnails = {
            '碳水': '/static/images/groceries.png',
            '蛋白质': '/static/images/groceries.png',
            '蔬果': '/static/images/groceries.png',
            '零食': '/static/images/groceries.png'
        }
        return category_thumbnails.get(category_name, '/static/images/groceries.png')


    @staticmethod
    def get_all_foods():
        """ 获取所有食品信息 """
        foods = Food.query.all()
        return foods

    @staticmethod
    def get_food_by_id(food_id):
        """ 根据食品ID获取食品信息 """
        food = Food.query.get(food_id)
        return food

    @staticmethod
    def get_foods_by_category(category_id, page=1, per_page=20):
        """ 根据类别ID分页获取食物列表 """
        # 查询指定类别的食物并分页
        food_pagination = Food.query.filter_by(category_id=category_id).paginate(page=page, per_page=per_page, error_out=False)
        # 获取分页数据
        foods = food_pagination.items  # 当前页的食物列表
        # 将结果转换为字典列表（可以选择返回你需要的字段）
        food_list = [
            {
                'id': food.food_id,
                'name': food.name,
                'category_id': food.category_id,
                'category' : food.category_2,
                'evaluation': food.evaluation,
                'carb': food.carbohydrate,
                'prot': food.protein,
                'fat': food.fat,
                'calories': food.calories,
                'img_name': food.img_name
                # 可以添加更多字段
            }
            for food in foods
        ]
        return food_pagination,food_list
        # return food_list

    def add_food_to_meal(self, meal_id,food_id, food_qty):
        # 验证 food_id 和 meal_id 是否有效
        food = Food.query.get(food_id)
        meal = Meal.query.get(meal_id)


        if not food or not meal:
            raise ValueError("Invalid food_id or meal_id")

        # 计算食品热量
        calories = food.calories * float(food_qty)

        meal_map = {
            "早餐": 1,
            "午餐": 2,
            "晚餐": 3,
            "零食": 4
        }
        mealNum = meal_map.get(meal.header)
        # print(meal_id,meal.header,mealNum,food_id)
        # 创建 MealFood 记录
        meal_food = MealFood(
            food_id=food_id,
            meal_id=meal_id,
            meal_num=mealNum,  # 默认餐次为1，可以根据实际需求修改
            quantity=food_qty,  # 默认份数为1
            calories=calories
        )

        # 保存记录到数据库
        db.session.add(meal_food)
        db.session.commit()

        # 更新 Meal 的总热量、碳水化合物、蛋白质、脂肪
        self._update_meal_nutrition(meal_id)
        # 更新 Recipe 的总热量、碳水化合物、蛋白质、脂肪
        self._update_recipe_nutrition(meal.recipe_id)

        return food.name,meal.header  # 返回新增的 MealFood 记录


    def delete_meal_food(self, meal_id, food_id):
        try:
            # 使用 joinedload 显式加载 meal 关系
            meal_food = db.session.query(MealFood).options(joinedload(MealFood.meal)).filter(
                MealFood.meal_id == int(meal_id),
                MealFood.food_id == int(food_id)
            ).one()

            # 获取 meal 对象
            meal = meal_food.meal  # 此时 meal 已经被加载

            # 删除 MealFood 记录
            db.session.delete(meal_food)
            db.session.commit()

            # 更新 Meal 的总营养信息
            self._update_meal_nutrition(meal_id)

            # 更新 Recipe 的总营养信息
            self._update_recipe_nutrition(meal.recipe_id)

            return {"message": "删除成功！"}, 200

        except NoResultFound:
            # 如果没有找到对应的记录
            return {"error": "MealFood record not found"}, 404

        except Exception as e:
            # 处理其他异常
            db.session.rollback()
            return {"error": str(e)}, 500

    @staticmethod
    def add_food(name, category_id, **kwargs):
        """ 添加新的食品 """
        food = Food(
            name=name,
            category_id=category_id,
            **kwargs
        )
        db.session.add(food)
        db.session.commit()
        return food

    @staticmethod
    def update_food(food_id, **kwargs):
        """ 更新食品信息 """
        food = Food.query.get(food_id)
        if food:
            for key, value in kwargs.items():
                setattr(food, key, value)
            db.session.commit()
            return food
        return None

    @staticmethod
    def delete_food(food_id):
        """ 删除食品 """
        food = Food.query.get(food_id)
        if food:
            db.session.delete(food)
            db.session.commit()
            return True
        return False


    def _update_meal_nutrition(self, meal_id):
        # print(meal_id)
        # 查询 Meal 和 MealFood 记录，计算总热量、碳水、蛋白质、脂肪
        meal = Meal.query.get(meal_id)
        meal_foods = MealFood.query.filter_by(meal_id=meal_id).all()

        total_calories = 0
        total_carbohydrate = 0
        total_protein = 0
        total_fat = 0

        for meal_food in meal_foods:
            total_calories += meal_food.calories
            food = Food.query.get(meal_food.food_id)
            total_carbohydrate += food.carbohydrate * meal_food.quantity
            total_protein += food.protein * meal_food.quantity
            total_fat += food.fat * meal_food.quantity

        # 更新 Meal 的营养信息
        meal.calories = total_calories
        meal.carbohydrate = total_carbohydrate
        meal.protein = total_protein
        meal.fat = total_fat

        db.session.commit()


    def _update_recipe_nutrition(self, recipe_id):
        # 查询 Recipe 和 Meal 记录，计算总热量、碳水、蛋白质、脂肪
        # print(recipe_id)
        recipe = Recipe.query.get(recipe_id)
        meals = Meal.query.filter_by(recipe_id=recipe_id).all()

        total_calories = 0
        total_carbohydrate = 0
        total_protein = 0
        total_fat = 0

        for meal in meals:
            total_calories += meal.calories or 0
            total_carbohydrate += meal.carbohydrate or 0
            total_protein += meal.protein or 0
            total_fat += meal.fat or 0

        # 更新 Recipe 的营养信息
        recipe.calories = total_calories
        recipe.carbohydrate = total_carbohydrate
        recipe.protein = total_protein
        recipe.fat = total_fat

        db.session.commit()

    @staticmethod
    def search_foods_by_keyword(keyword):
        """
        Search for foods by keyword matching the name field
        
        Args:
            keyword (str): Search term to match against food names
        
        Returns:
            list: A list of food dictionaries matching the search term
        """
        # Use case-insensitive partial matching with SQLAlchemy
        foods = Food.query.filter(
            Food.name.ilike(f'%{keyword}%')
        ).all()
        
        # Convert to list of dictionaries for JSON serialization
        return [
            {
                'id': food.food_id,
                'name': food.name,
                'category_id': food.category_id,
                'category': food.category_2,
                'evaluation': food.evaluation,
                'calories': food.calories,
                'prot': food.protein,
                'carb': food.carbohydrate,
                'fat': food.fat,
                'img_name': food.img_name
            } for food in foods
        ]

    @staticmethod
    def get_similar_foods(food_id):
        # Find the MealFood record with the given food_id
        meal_food = MealFood.query.filter_by(food_id=food_id).first()
        
        # If no record found, raise NoResultFound exception
        if not meal_food:
            raise NoResultFound(f"No food found with ID {food_id}")
        
        # If no related foods are stored, return an empty list
        if not meal_food.related_foods:
            return []
        
        # Parse the related foods (assuming it's stored as a string representation of a list)
        import ast
        related_food_names = ast.literal_eval(meal_food.related_foods)
        
        # Find foods with these names
        similar_foods = Food.query.filter(Food.name.in_(related_food_names)).all()
        
        # Convert to dictionary for JSON serialization
        return [food.to_dict() for food in similar_foods]